#include "ui.h"
#include "sys.h"
#include "expr.h"
#include "string.h"

#define cmd_handler(cmd) static int cmd(char *args)

void core_main();

cmd_handler(fuck) {
  puts("Sit back and relax.", 0);
  return 0;
}

cmd_handler(hello) {
  puts("Hello, World!", 0);
  return 0;
}

cmd_handler(echo) {
  if (args)
    puts(args, 0);
  return 0;
}

cmd_handler(cmd_fib) {
  if (args) {
    unsigned u = fib(atoi(args, 10));
    char res[100];
    puts(itoa(u, res, 10), 0);
    return 0;
  }
  return 0;
}

cmd_handler(p) {
  char buf[100];
  eval(args, buf);
  puts(buf, 0);
  return 0;
}

cmd_handler(clear) {
  vga_init();
  return 0;
}
cmd_handler(help);
cmd_handler(cmd_time) {
  mouse_invisible = true;
  do {
    TIME t = time();
    uint16_t s = t.s;
    uint16_t min = t.min;
    uint16_t hour = t.hr;
    char time_buf[100];
    itoa(hour, time_buf, 10);
    int len1 = strlen(time_buf);
    putstr(time_buf, 0);
    putstr(":", 0);
    itoa(min, time_buf, 10);
    int len2 = strlen(time_buf);
    putstr(time_buf, 0);
    putstr(":", 0);
    itoa(s, time_buf, 10);
    int len3 = strlen(time_buf);
    putstr(time_buf, 0);
    putstr("     ", 0);
    for (int i = 0; i < len1 + len3 + len2 + 2 + 5; ++i, putstr("\b", 0))
      ;
  } while (head == *key_tail);
  getch();
  puts("", 0);
  mouse_invisible = false;
  return 0;
}

cmd_handler(bcolor) {
  int select = atoi(args, 10);
  user_color.bcolor = select;
  return 0;
}

cmd_handler(fcolor) {
  int select = atoi(args, 10);
  user_color.fcolor = select;
  return 0;
}

cmd_handler(mark) {
  core_main();
  return 0;
}

static struct {
  char *name;
  char *description;
  int (*handler)(char *);
} cmd_table[] = {
    {"help", "Display informations about all supported commands", help},
    {"p", "Evaluate an expression", p},
    {"echo", "Repeater", echo},
    {"hello", "Brings you good mood :)", hello},
    {"fuck", "Comforts you :(", fuck},
    {"fib", "Calculate fib(x), usage : fib [x]", cmd_fib},
    {"time", "Show time :)", cmd_time},
    {"clear", "Clear screen", clear},
    {"bcolor", "Set your background color", bcolor},
    {"fcolor", "Set your foreground color", fcolor},
    {"mark", "Run CoreMark to see the score :)", mark},
};

#define NR_CMD (sizeof(cmd_table) / sizeof(cmd_table[0]))
cmd_handler(help) {
  if (args[0] == '\0') {
    for (int i = 0; i < NR_CMD; ++i) {
      putstr(cmd_table[i].name, 0);
      putstr("\t-\t", 0);
      puts(cmd_table[i].description, 0);
    }
  } else {
    for (int i = 0; i < NR_CMD; ++i) {
      if (!strcmp(cmd_table[i].name, args)) {
        putstr(cmd_table[i].name, 0);
        putstr("\t-\t", 0);
        puts(cmd_table[i].description, 0);
        return 0;
      }
    }
    putstr("Unknown user command : ", 0);
    puts(args, 0);
  }
  return 0;
}
void ui_mainloop() {
  while (true) {
    // read user command
    char user_cmd[1000];
    for (int i = 0; i < 1000; ++i) {
      user_cmd[i] = '\0';
    }
    gets("baka@zcy", "~", user_cmd);
    if (user_cmd[0] == '\0') {
      putch('\n', 0);
      continue;
    }
    char *user_cmd_end = user_cmd + strlen(user_cmd);
    // parse the command
    char *cmd = strtok(user_cmd, " ");
    if (cmd == NULL) {
      // empty command, should not happen
      continue;
    }

    // the remaining part of user_cmd is considered as arguments
    char *args = user_cmd + strlen(cmd) + 1;
    args += strspn(args, " ");
    if (args >= user_cmd_end) {
      // there is no argument
      args = NULL;
    }

    // execute the command by calling corresponding function
    int i;
    for (i = 0; i < NR_CMD; i++) {
      if (strcmp(cmd, cmd_table[i].name) == 0) {
        cmd_table[i].handler(args);
        // stop searching for cmd and wait for the next user_cmd
        break;
      }
    }

    if (i == NR_CMD) {
      putstr("Unknown user command : ", 0);
      puts(user_cmd, 0);
    }
  }
}